﻿using System;
using System.Collections.Generic;
using Kaleida.ServiceMonitor.Framework;
using Kaleida.ServiceMonitor.Model.Runtime;
using Kaleida.ServiceMonitor.Model.StructuredSource;
using NUnit.Framework;

namespace Kaleida.UnitTests.Model.Runtime
{
    [TestFixture]
    public class ScriptCompilerTests
    {
        private readonly OperationDefinition[] emptyCommandList = new OperationDefinition[0];
        private readonly string[] emptyCommentList = new string[0];
        private readonly DirectiveDefinition[] emptyDirectiveList = new DirectiveDefinition[0];

        [Test]
        public void TestIfOrderingNotExplicitUseRoundRobin()
        {
            var scriptDefinition = new ScriptDefinition(emptyDirectiveList, emptyCommandList, emptyCommentList);
            var script = new ScriptCompiler().Build(scriptDefinition);

            Assert.AreEqual(OperationOrder.RoundRobin, script.ExecutionOrder);
        }

        [Test]
        public void TestCanSetOrderingFromDefinitionWithSoleDirective()
        {
            var directives = new[] {new DirectiveDefinition("order", new[] {"random"})};
            var scriptDefinition = new ScriptDefinition(directives, emptyCommandList, emptyCommentList);
            var script = new ScriptCompiler().Build(scriptDefinition);

            Assert.AreEqual(OperationOrder.Random, script.ExecutionOrder);
        }

        [Test]
        public void TestCanSetOrderingWhenConflictingDirectivesFound()
        {
            var directives = new[] { new DirectiveDefinition("order", new[] { "round-robin" }), new DirectiveDefinition("order", new[] { "random" }) };
            var scriptDefinition = new ScriptDefinition(directives, emptyCommandList, emptyCommentList);
            var script = new ScriptCompiler().Build(scriptDefinition);

            Assert.AreEqual(OperationOrder.Random, script.ExecutionOrder, "The last directive encountered is used");
        }

        [Test]
        public void TestCanSetFrequency()
        {
            var scriptDefinition = new ScriptDefinition(new[] { new DirectiveDefinition("poll-frequency", new[]{"1500"}) }, emptyCommandList, emptyCommentList);
            var script = new ScriptCompiler().Build(scriptDefinition);

            Assert.AreEqual(1500, script.PollFrequency.Value);
            Assert.AreEqual("ms", script.PollFrequency.Suffix);
        }

        [Test]
        public void TestFrequencyIs1000IfNotExplicitlySet()
        {
            var scriptDefinition = new ScriptDefinition(emptyDirectiveList, emptyCommandList, emptyCommentList);
            var script = new ScriptCompiler().Build(scriptDefinition);

            Assert.AreEqual("1000 ms", script.PollFrequency.ToString());
        }

        [Test]
        public void TestCommandNamesAreResolvedAndAssembled()
        {
            var commands = new[]
                               {
                                   new OperationDefinition(new ActionDefinition("my-command"), new ActionDefinition("my-handler")),
                                   new OperationDefinition(new ActionDefinition("my-other-command", new[] {"arg1", "arg2"}), new ActionDefinition("my-other-handler", new[] {"a"}))
                               };
            var scriptDefinition = new ScriptDefinition(emptyDirectiveList, commands, emptyCommentList);
            
            var mockFactory = new MockcommandFactory();
            var builder = new ScriptCompiler(mockFactory, mockFactory);
            var script = builder.Build(scriptDefinition);

            Assert.AreEqual(2, script.Operations.Count);
            Assert.AreEqual("DummyPreparedRequest and DummyResponseHandler", script.Operations[0].Description);
            Assert.AreEqual("DummyPreparedRequest and DummyResponseHandler", script.Operations[1].Description);
        }

        private class MockcommandFactory : IPreparedRequestFactory, IResponseHandlerFactory
        {
            PreparedRequest IPreparedRequestFactory.Build(string name, IList<string> arguments)
            {
                return new DummyPreparedRequest();
            }

            ResponseHandler IResponseHandlerFactory.Build(string name, IList<string> arguments)
            {
                return new DummyResponseHandler();
            }
        }

        private class DummyPreparedRequest : PreparedRequest
        {
            public override string Description
            {
                get { return "DummyPreparedRequest"; }
            }

            public override object GetResponse()
            {
                return 1;
            }
        }

        private class DummyResponseHandler : ResponseHandler
        {
            public override string Description
            {
                get { return "DummyResponseHandler"; }
            }

            public override string ProcessResponse(object response)
            {
                return "";
            }
        }
    }
}
